package com.khstudio.filebrowser.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

import android.app.Activity;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.webkit.MimeTypeMap;

import com.khstudio.filebrowser.util.KhDialogProgress.KhFileDialogListener;

public class KhFile {
    private static final int    MODE_COPY           = 0x0001;
    private static final int    MODE_MOVE           = 0x0002;
    private static final int    MODE_DELETE         = 0x0003;
    private static final int    MODE_RENAME         = 0x0004;
    private static final int    MODE_CREATE_FOLDER  = 0x0005;

    private static final int    MSG_PROGRESS            = 0x0001;
    private static final int    MSG_DIALOG_COMPLETE     = 0x0002;
    private static final int    MSG_PROGRESS_COMPLETE   = 0x0003;
    private static final int    MSG_PROGRESS_ERROR      = 0x0004;

    private KhFileListener      mListener;
    private KhDialogProgress    mDialogPr;
    private KhDialog            mDialog;

    private ArrayList<String>   mSrcList;
    private String              mTarDir;
    private ArrayList<String>   mResultList;

    private int                 mMode;

    private long                mProgressTSize;
    private long                mProgressCSize;
    private int                 mProgressCnt;
    private int                 mProgressValue;

    private boolean             mRunning;

    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_PROGRESS:
                    mDialogPr.setCount(msg.arg1);
                    mDialogPr.setProgress(msg.arg2);
                break;
                case MSG_DIALOG_COMPLETE:
                    mDialog.dismiss();
                    _done();
                break;
                case MSG_PROGRESS_COMPLETE:
                    mDialogPr.dismiss();
                    _done();
                break;
                case MSG_PROGRESS_ERROR:
                    mDialogPr.dismiss();
                    _done();
                break;
            }
        }
    };

    public interface KhFileListener {
        void onDone(ArrayList<String> result);
    }

    public static KhFile copy(Activity c, ArrayList<String> in, String outDir, KhFileListener l) {
        return new KhFile(MODE_COPY, c, in, outDir, l);
    }

    public static KhFile move(Activity c, ArrayList<String> in, String outDir, KhFileListener l) {
        return new KhFile(MODE_MOVE, c, in, outDir, l);
    }

    public static KhFile delete(Activity c, ArrayList<String> in, KhFileListener l) {
        return new KhFile(MODE_DELETE, c, in, null, l);
    }

    public static KhFile rename(Activity c, String in, KhFileListener l) {
        ArrayList<String> src = new ArrayList<String>();
        src.add(in);
        return new KhFile(MODE_RENAME, c, src, null, l);
    }

    public static KhFile createfolder(Activity c, String outdir, KhFileListener l) {
        return new KhFile(MODE_CREATE_FOLDER, c, null, outdir, l);
    }

    public static String getMimeType(String url)
    {
        String type = null;

        int filenamePos = url.lastIndexOf('/');
        String filename = 0 <= filenamePos ? url.substring(filenamePos + 1) : url;

        int dotPos = filename.lastIndexOf('.');
        String extension = 0 <= dotPos ? filename.substring(dotPos + 1) : filename;

        if (extension != null) {
            MimeTypeMap mime = MimeTypeMap.getSingleton();
            type = mime.getMimeTypeFromExtension(extension);
        }
        return type;
    }

    private KhFile(int mode, Activity c, ArrayList<String> src, String target, KhFileListener l) {
        mListener = l;
        mMode = mode;
        mResultList = new ArrayList<String>();

        if(mode == MODE_COPY) {
            _copy(c, src, target);
        } else if(mode == MODE_MOVE) {
            _move(c, src, target);
        } else if(mode == MODE_DELETE) {
            _delete(c, src);
        } else if(mode == MODE_RENAME) {
            _rename(c, src);
        } else if(mode == MODE_CREATE_FOLDER) {
            _createfolder(c, target);
        }
    }

    private void _copy(Activity c, ArrayList<String> src, String tarDir) {
        mSrcList = src;
        mTarDir  = tarDir;
        mRunning = true;

        mDialogPr = KhDialogProgress.show(c.getFragmentManager(), "Copy", src.size(), new KhFileDialogListener() {
            @Override
            public void onClickCancel() {
                mRunning = false;
            }
        });

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    mProgressTSize = 0;
                    mProgressCSize = 0;
                    mProgressCnt = 0;
                    mProgressValue = 0;
                    for(String in : mSrcList) {
                        if(!mRunning) {
                            return;
                        }
                        File file = new File(in);
                        mProgressTSize += file.length();
                    }

                    for(int i = 0; i < mSrcList.size() && mRunning; i++) {
                        File in = new File(mSrcList.get(i));
                        File out = _createOutputFile(mTarDir + File.separator + in.getName());

                        mProgressCnt = i+1;
                        _copy(in, out);

                        if(!mRunning) _delete(out);

                    }
                    _completeProgress();
                } catch (IOException e) {
                    e.printStackTrace();
                    _errorProgress();
                }
            }
        }).start();
    }

    private void _copy(File in, File out) throws IOException {
        FileInputStream         inputStream = null;
        FileOutputStream        outputStream = null;
        BufferedInputStream     bin = null;
        BufferedOutputStream    bout = null;

        try {
            inputStream = new FileInputStream(in);
            outputStream = new FileOutputStream(out);
            bin = new BufferedInputStream(inputStream);
            bout = new BufferedOutputStream(outputStream);

            int bytesRead = 0;
            byte[] buffer = new byte[1024];
            int newprogress = 0;
            while ((bytesRead = bin.read(buffer, 0, 1024)) != -1 && mRunning) {
                bout.write(buffer, 0, bytesRead);
                mProgressCSize += bytesRead;
                newprogress = (int)(mProgressCSize * 100 / mProgressTSize);

                if(newprogress > mProgressValue && mProgressValue <= 100) {
                    mProgressValue = newprogress;
                    _progress();
                }
            }
            mResultList.add(out.getPath());
        } finally {
            bout.close();
            bin.close();
            outputStream.close();
            inputStream.close();
        }
    }

    private void _move(Activity c, ArrayList<String> src, String tarDir) {
        mSrcList = src;
        mTarDir  = tarDir;
        mRunning = true;

        mDialogPr = KhDialogProgress.show(c.getFragmentManager(), "Move", src.size(), new KhFileDialogListener() {
            @Override
            public void onClickCancel() {
                mRunning = false;
            }
        });

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    mProgressTSize = 0;
                    mProgressCSize = 0;
                    mProgressCnt = 0;
                    mProgressValue = 0;
                    for(String in : mSrcList) {
                        if(!mRunning) {
                            return;
                        }
                        File file = new File(in);
                        mProgressTSize += file.length();
                    }

                    for(int i = 0; i < mSrcList.size() && mRunning; i++) {
                        File in = new File(mSrcList.get(i));
                        File out = _createOutputFile(mTarDir + File.separator + in.getName());

                        mProgressCnt = i+1;
                        _move(in, out);

                        if(!mRunning) _delete(out);
                    }
                    _completeProgress();
                } catch (IOException e) {
                    e.printStackTrace();
                    _errorProgress();
                }
            }
        }).start();
    }

    private void _move(File in, File out) throws IOException {
        if(!in.renameTo(out)) {
            _copy(in, out);
            _delete(in);
        } else {
            mProgressCSize += in.length();
            mProgressValue = (int)(mProgressCSize * 100 / mProgressTSize);
            mResultList.add(out.getPath());
        }
    }

    private void _delete(Activity c, ArrayList<String> src) {
        mSrcList = src;
        mRunning = true;

        mDialogPr = KhDialogProgress.show(c.getFragmentManager(), "Delete", src.size(), new KhFileDialogListener() {
            @Override
            public void onClickCancel() {
                mRunning = false;
            }
        });

        new Thread(new Runnable() {
            @Override
            public void run() {
                int totalcnt = mSrcList.size();
                mProgressTSize = totalcnt;
                mProgressCSize = 0;
                mProgressCnt = 0;
                mProgressValue = 0;

                for(int i = 0; i < totalcnt && mRunning; i++) {
                    File src = new File(mSrcList.get(i));
                    _delete(src);
                    mProgressCnt = i+1;
                    mProgressCSize = i+1;
                    mProgressValue = (int)(mProgressCSize * 100 / mProgressTSize);
                    _progress();
                }
                _completeProgress();
            }
        }).start();
    }

    private void _delete(File f) {
        if(f.exists()) {
            f.delete();
            mResultList.add(f.getPath());
        }
    }

    private void _rename(Activity c, ArrayList<String> src) {
        mSrcList = src;
        File file = new File(mSrcList.get(0));
        mTarDir = file.getParent();

        mDialog = KhDialog.showDialogEdit(c.getFragmentManager(), "Rename", null, file.getName());
        mDialog.setPositiveButton(c.getResources().getString(android.R.string.ok), new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String name = mDialog.getEditText();
                _rename(mSrcList.get(0), mTarDir + File.separator + name);
                _completeDialog();
            }
        });
        mDialog.setCancelButton(c.getResources().getString(android.R.string.cancel), new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                _completeDialog();
            }
        });
    }

    private boolean _rename(String in, String out) {
        File inFile = new File(in);
        File outFile = new File(out);

        if(inFile.exists() && !outFile.exists()) {
            if(inFile.renameTo(outFile)) {
                mResultList.add(outFile.getPath());
                return true;
            }
        }
        return false;
    }

    private void _createfolder(Activity c, String tarDir) {
        mTarDir = tarDir;

        mDialog = KhDialog.showDialogEdit(c.getFragmentManager(), "Add folder", null, null);
        mDialog.setPositiveButton(c.getResources().getString(android.R.string.ok), new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String name = mDialog.getEditText().equals("") ? "new" : mDialog.getEditText();
                if(_createfolder(mTarDir + File.separator + name)) {
                    _completeDialog();
                }
            }
        });
        mDialog.setCancelButton(c.getResources().getString(android.R.string.cancel), new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                _completeDialog();
            }
        });
    }

    public boolean _createfolder(String src) {
        if(src == null) {
            return false;
        }
        else {
            File f = _createOutputFile(src);

            if(f.mkdir() && f.isDirectory()) {
                mResultList.add(f.getPath());
                return true;
            }
            return false;
        }
    }

    private File _createOutputFile(String in) {
        File outFile = new File(in);

        while(outFile.exists()) {
            String path = outFile.getPath();

            int index = path.lastIndexOf(String.valueOf('.'));
            String extention = null;
            String outname = null;
            if(index > 0) {
                outname = path.substring(0, index);
                extention = path.substring(index);
            } else {
                outname = path;
            }
            KhLog.i("_createOutputFile outname = "+outname);
            if(mMode == MODE_COPY) {
                outFile = new File(outname + "_copy" + (extention == null ? "" : extention));
            } else if(mMode == MODE_MOVE) {
                outFile = new File(outname + "_move" + (extention == null ? "" : extention));
            } else if(mMode == MODE_RENAME) {
                outFile = new File(outname + "_rename" + (extention == null ? "" : extention));
            } else if(mMode == MODE_CREATE_FOLDER) {
                outFile = new File(outname + "_folder" + (extention == null ? "" : extention));
            } else {
                return null;
            }
        }

        return outFile;
    }

    private void _progress() {
        mHandler.removeMessages(MSG_PROGRESS);
        Message msg = mHandler.obtainMessage();
        msg.what = MSG_PROGRESS;
        msg.arg1 = mProgressCnt;
        msg.arg2 = mProgressValue;
        mHandler.sendMessage(msg);
    }

    private void _completeDialog() {
        mHandler.sendEmptyMessage(MSG_DIALOG_COMPLETE);
    }

    private void _completeProgress() {
        mHandler.sendEmptyMessageDelayed(MSG_PROGRESS_COMPLETE, 500);
    }

    private void _errorProgress() {
        mHandler.sendEmptyMessage(MSG_PROGRESS_ERROR);
    }

    private void _done() {
        if(mListener != null) mListener.onDone((mResultList.size() == 0) ? null : mResultList);
    }
}
